// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license

#include "stdafx.h"
#include "WorldBuilder.h"
#include "Node.h"
#include "NodeManager.h"
#include "Sphere.h"
#include "AABB.h"

Node::Node()
: m_nodeManager(NULL),
  m_globalTransformReady(false),
  m_globalTransform(gx::eye)
{
}

Node::~Node()
{
}

void Node::drawAabb() const 
{
    glPushMatrix();
    glPushAttrib(GL_LIGHTING_BIT | GL_CURRENT_BIT);

        double m[16];
        glMultMatrixd(getGlobalTransform().to_array(m));
        // TODO this can be made part of glMultMatrix 

        glDisable(GL_LIGHTING);
        AABB aabb = getAabbLocal();
        glTranslated(aabb.center.x, aabb.center.y, aabb.center.z);
        glScaled(aabb.dims.x, aabb.dims.y, aabb.dims.z);
        glutWireCube(1.);
    
    glPopAttrib();
    glPopMatrix();
}

void Node::invalidateGlobalTransform() const
{
    m_globalTransformReady = false;
    if(hasValidIterator())
    {
        NodeSiblingIterator it = getChildrenBegin();
        for(; it != getChildrenEnd(); ++it)
        {
            (*it)->invalidateGlobalTransform();
        }
    }
}

gx::Mat4 Node::getGlobalTransform() const 
{ 
    if(!m_globalTransformReady)
    {
        if(const Transformable* this_ = dynamic_cast<const Transformable*>(this))
        {
            m_globalTransform = getParentGlobalTransform() * this_->getLocalTransform(); 
        }
        else
        {
            m_globalTransform = getParentGlobalTransform();
        }
        m_globalTransformReady = true;
    }
    return m_globalTransform;
}

bool Node::isBoundedImpl() const 
{ 
    return false; 
}


AABB Node::getAabbLocal() const 
{ 
    ASSERT(isBounded()); 
    return getAabbLocalImpl();
}

bool Node::canBeDrawnImpl() const 
{ 
    return false; 
}

void Node::draw(View3d*) const 
{ 
    ASSERT(!canBeDrawn()); 
}


AABB Node::getAabbLocalImpl() const 
{ 
    ASSERT(!isBounded()); 
    return AABB();
}

gx::Mat4 Node::getParentGlobalTransform() const
{
    Node* parent = getParent();
    if(parent != NULL)
    {
        return parent->getGlobalTransform();
    }
    return gx::eye;
}

Node* Node::getParent() const 
{ 
    if(!hasValidIterator())
    {
        return NULL;
    }

    if(getIterator().node->parent == NULL)
    {
        return NULL;
    }
    return getIterator().node->parent->data.get();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

NodeIterator Node::getIterator() const
{ 
    ASSERT(hasValidIterator());
    return m_iterator; 
}

bool Node::hasValidIterator() const
{
    return m_iterator.node != NULL;
}

void Node::setIterator(NodeIterator it)
{
    m_iterator = it;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

void Node::notifyPropertyChange(NodeEvent::Property property_)
{
    if(m_nodeManager != NULL)
    {
        m_nodeManager->notifyNodePropertyChanged(this, property_);
    }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


NodeSiblingIterator Node::getChildrenBegin() const
{
    return getIterator().begin();
}

NodeSiblingIterator Node::getChildrenEnd() const
{
    return getIterator().end();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Serialization

void Node::read(std::wistream& is)
{
    Selectable::read(is);

}

void Node::write(std::wostream& os) const
{
    Selectable::write(os);
 
}


